#include "../mqserver/mq_binding.hpp"
#include <gtest/gtest.h>

using namespace zdfmq;

BindingManager::ptr bmp;

class QueueTest : public testing::Environment
{
public:
    virtual void SetUp() override
    {
        // 初始化绑定管理器并连接到测试数据库
        bmp = std::make_shared<BindingManager>("./data/meta.db");
        // 清除所有现有绑定，确保测试环境干净
        bmp->clear();
    }

    virtual void TearDown() override
    {
        // 测试结束后清理所有绑定
        bmp->clear();
    }
};

// 测试绑定操作
TEST(queue_test, insert_test)
{
    // 添加6个不同的绑定关系
    bmp->bind("exchange1", "queue1", "news.music.#", true);
    bmp->bind("exchange1", "queue2", "news.sport.#", true);
    bmp->bind("exchange1", "queue3", "news.gossip.#", true);
    bmp->bind("exchange2", "queue1", "news.music.pop", true);
    bmp->bind("exchange2", "queue2", "news.sport.football", true);
    bmp->bind("exchange2", "queue3", "news.gossip.#", true);

    // 验证绑定总数
    ASSERT_EQ(bmp->size(), 6);
}

// 测试绑定查询功能
TEST(queue_test, select_test)
{
    // 先插入测试数据
    bmp->bind("exchange1", "queue1", "news.music.#", true);
    bmp->bind("exchange1", "queue2", "news.sport.#", true);
    bmp->bind("exchange2", "queue3", "news.gossip.#", true);

    // 验证绑定是否存在
    ASSERT_EQ(bmp->exists("exchange1", "queue1"), true);
    ASSERT_EQ(bmp->exists("exchange1", "queue2"), true);
    ASSERT_EQ(bmp->exists("exchange1", "queue3"), true); 
    ASSERT_EQ(bmp->exists("exchange2", "queue3"), true);

    // 获取特定绑定并验证属性
    Binding::ptr bp = bmp->getBinding("exchange1", "queue1");
    ASSERT_NE(bp.get(), nullptr);
    ASSERT_EQ(bp->exchange_name, "exchange1");
    ASSERT_EQ(bp->msgqueue_name, "queue1");
    ASSERT_EQ(bp->binding_key, "news.music.#");
}

// 测试按交换机查询绑定
TEST(queue_test, select_exchange_test)
{
    // 为exchange1添加3个绑定
    bmp->bind("exchange1", "queue1", "news.music.#", true);
    bmp->bind("exchange1", "queue2", "news.sport.#", true);
    bmp->bind("exchange1", "queue3", "news.gossip.#", true);

    // 为exchange2添加2个绑定
    bmp->bind("exchange2", "queue1", "news.music.pop", true);
    bmp->bind("exchange2", "queue2", "news.sport.football", true);

    // 获取exchange1的所有绑定
    MsgQueueBindingMap mqbm = bmp->getExchangeBindings("exchange1");

    // 验证绑定数量和队列名称
    ASSERT_EQ(mqbm.size(), 3);
    ASSERT_NE(mqbm.find("queue1"), mqbm.end());
    ASSERT_NE(mqbm.find("queue2"), mqbm.end());
    ASSERT_NE(mqbm.find("queue3"), mqbm.end());
}

// 测试删除队列的所有绑定
TEST(queue_test, remove_queue_test)
{
    // 为queue1添加多个绑定
    bmp->bind("exchange1", "queue1", "news.music.#", true);
    bmp->bind("exchange2", "queue1", "news.music.pop", true);
    bmp->bind("exchange3", "queue1", "special.#", true);

    // 删除queue1的所有绑定
    bmp->removeMsgQueueBindings("queue1");

    // 验证所有绑定已删除
    ASSERT_EQ(bmp->exists("exchange1", "queue1"), false);
    ASSERT_EQ(bmp->exists("exchange2", "queue1"), false);
    ASSERT_EQ(bmp->exists("exchange3", "queue1"), false);
}

// 测试删除交换机的所有绑定
TEST(queue_test, remove_exchange_test)
{
    // 为exchange1添加多个绑定
    bmp->bind("exchange1", "queue1", "news.music.#", true);
    bmp->bind("exchange1", "queue2", "news.sport.#", true);
    bmp->bind("exchange1", "queue3", "news.gossip.#", true);

    // 删除exchange1的所有绑定
    bmp->removeExchangeBindings("exchange1");

    // 验证所有绑定已删除
    ASSERT_EQ(bmp->exists("exchange1", "queue1"), false);
    ASSERT_EQ(bmp->exists("exchange1", "queue2"), false);
    ASSERT_EQ(bmp->exists("exchange1", "queue3"), false);

    // 确保其他交换机的绑定不受影响
    bmp->bind("exchange2", "queue1", "news.music.pop", true);
    ASSERT_EQ(bmp->exists("exchange2", "queue1"), true);
}

// 测试删除单个绑定
TEST(queue_test, remove_single_test)
{
    // 添加两个绑定
    bmp->bind("exchange2", "queue2", "news.sport.football", true);
    bmp->bind("exchange2", "queue3", "news.gossip.#", true);

    // 验证绑定存在
    ASSERT_EQ(bmp->exists("exchange2", "queue2"), true);
    ASSERT_EQ(bmp->exists("exchange2", "queue3"), true);

    // 删除单个绑定
    bmp->unbind("exchange2", "queue2");

    // 验证指定绑定已删除，其他绑定保持不变
    ASSERT_EQ(bmp->exists("exchange2", "queue2"), false);
    ASSERT_EQ(bmp->exists("exchange2", "queue3"), true);
}

int main(int argc, char *argv[])
{
    testing::InitGoogleTest(&argc, argv);
    testing::AddGlobalTestEnvironment(new QueueTest);
    return RUN_ALL_TESTS();
}